package com.zbkj.crmeb.finance.service.process;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.constants.Constants;
import com.constants.WeChatConstants;
import com.crmeb.core.exception.CrmebException;
import com.utils.CrmebUtil;
import com.utils.RestTemplateUtil;
import com.utils.WxPayUtil;
import com.utils.XmlUtil;
import com.zbkj.crmeb.finance.model.UserRecharge;
import com.zbkj.crmeb.finance.service.UserRechargeService;
import com.zbkj.crmeb.front.request.UserRechargeRequest;
import com.zbkj.crmeb.payment.vo.hkwechat.HkPayAttachVo;
import com.zbkj.crmeb.payment.vo.hkwechat.HkPayPaymentRequest;
import com.zbkj.crmeb.payment.vo.hkwechat.HkPayPaymentResponse;
import com.zbkj.crmeb.system.model.SystemConfig;
import com.zbkj.crmeb.system.service.SystemConfigService;
import com.zbkj.crmeb.system.service.SystemGroupDataService;
import com.zbkj.crmeb.system.vo.SystemGroupDataRechargeConfigVo;
import com.zbkj.crmeb.user.model.UserToken;
import com.zbkj.crmeb.user.service.UserService;
import com.zbkj.crmeb.user.service.UserTokenService;


/**
 * @ClassName: HkPayRechargeProcess
 * @Description: 香港支付充值订单
 */
@Service("hkpayRechargeProcess")
public class HkPayRechargeProcess implements IRechargeOrderProcess {
    public static final Logger logger = LoggerFactory.getLogger(HkPayRechargeProcess.class);

    @Autowired
    private SystemConfigService systemConfigService;
    @Autowired
    private SystemGroupDataService systemGroupDataService;
    @Autowired
    private UserService userService;
    @Autowired
    private UserRechargeService userRechargeService;
    @Autowired
    private UserTokenService userTokenService;
    @Autowired
    private RestTemplateUtil restTemplateUtil;

    @Override
    public Map<String, Object> rechage(UserRechargeRequest request) throws Exception {
        request.setPayments(Constants.PAY_TYPE_HK_PAY);
        //验证金额是否为最低金额
        String rechargeMinAmountStr = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_RECHARGE_MIN_AMOUNT);
        BigDecimal rechargeMinAmount = new BigDecimal(rechargeMinAmountStr);
        int compareResult = rechargeMinAmount.compareTo(request.getPrice());
        if(compareResult > 0){
            throw new CrmebException("充值金额不能低于" + rechargeMinAmountStr);
        }
        if(request.getGroupDataId() > 0){
            SystemGroupDataRechargeConfigVo systemGroupData = systemGroupDataService.getNormalInfo(request.getGroupDataId(), SystemGroupDataRechargeConfigVo.class);
            if(null == systemGroupData){
                throw new CrmebException("您选择的充值方式已下架");
            }

            //售价和赠送
            request.setPrice(systemGroupData.getPrice());
            request.setGivePrice(BigDecimal.ZERO);
        }
        //生成系统订单
        request.setUserId(userService.getUserIdException());

        UserRecharge userRecharge = userRechargeService.create(request);
        //支付调用请求
        HkPayPaymentRequest paymentRequest = getHkPayPaymentRequest(request,userRecharge);
        logger.info("请求香港支付充值参数,param:{} ------- sign:{}", JSONObject.toJSONString(paymentRequest), paymentRequest.getSign());
        String param = XmlUtil.objectToXml(paymentRequest);
        logger.info("请求香港支付充值参数,orderId:{},xml:{}",userRecharge.getOrderId(),param);
        String xml = restTemplateUtil.postXml(WeChatConstants.HK_PAY_API_URL, param);
        logger.info("请求香港支付充值参数响应,orderId:{},xml:{}",userRecharge.getOrderId(),xml);
        if (StringUtils.isBlank(xml)){
            logger.info("香港支付充值接口调用失败");
           throw new CrmebException("香港支付充值接口调用失败");
        }
        //解析xml
        HashMap<String, Object> map = XmlUtil.xmlToMap(xml);
        HkPayPaymentResponse paymentResponse = CrmebUtil.mapToObj(map, HkPayPaymentResponse.class);
        if (!"0".equals(paymentResponse.getStatus())){
            throw new CrmebException(paymentResponse.getMessage());
        }
        if (!"0".equals(paymentResponse.getResult_code())){
            throw new CrmebException(paymentResponse.getErr_msg());
        }
        Map<String, Object> resultMap = new HashMap<>();

        resultMap.put("data", paymentResponse);
        resultMap.put("status", "HK_PAY");
        resultMap.put("type", request.getFromType());

        return resultMap;
    }

    private HkPayPaymentRequest getHkPayPaymentRequest(UserRechargeRequest request, UserRecharge userRecharge) throws Exception {
        HkPayPaymentRequest paymentRequest = new HkPayPaymentRequest();
        //获取商户号 密钥
        String mchId = getSysConfigValue(WeChatConstants.HK_PAY_MCH_ID,request.getMerId());
        String secretKey = getSysConfigValue(WeChatConstants.HK_PAY_SECRET_KEY,request.getMerId());
        String appId = getSysConfigValue(WeChatConstants.HK_PAY_APPID,request.getMerId());

        paymentRequest.setService(WeChatConstants.HK_PAY_JSPAY_SERVICE);
        paymentRequest.setVersion("2.0");
        paymentRequest.setCharset("UTF-8");
        paymentRequest.setSign_type("MD5");
        paymentRequest.setMch_id(mchId);
        paymentRequest.setIs_raw("1");//是否原生态 值為 1：是；值為 0：否；不傳默認是 0
        paymentRequest.setIs_minipg("1");//是否小程序支付 值為 1，表示小程式支付；不傳或值不為 1， 表示公眾帳號內支付
        paymentRequest.setOut_trade_no(userRecharge.getOrderId());
        paymentRequest.setBody("充值");
//        paymentRequest.setBody("商品描述");
        //用户id 查询openId
        Integer userId = request.getUserId();
        UserToken userToken = userTokenService.getOne(Wrappers.<UserToken>lambdaQuery().eq(UserToken::getUid, userId));
        paymentRequest.setSub_openid(userToken.getToken());
        paymentRequest.setSub_appid(appId);
        //TODO 增加用户id等校验
        HkPayAttachVo attachVo = new HkPayAttachVo();
        attachVo.setUserId(userId);
        attachVo.setType("recharge");
        paymentRequest.setAttach(JSON.toJSONString(attachVo));
//        paymentRequest.setAttach("商户附加资讯");
        paymentRequest.setTotal_fee(request.getPrice().multiply(BigDecimal.TEN).multiply(BigDecimal.TEN).intValue());
        paymentRequest.setMch_create_ip(request.getClientIp());
        String domain = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_API_URL);
        paymentRequest.setNotify_url(domain + WeChatConstants.PAY_NOTIFY_API_URI_HKRECHARGE);
//        paymentRequest.setCallback_url("");
//        paymentRequest.setTime_start("");
//        paymentRequest.setTime_expire("");
//        paymentRequest.setGoods_tag("");
        paymentRequest.setNonce_str(getRandomStringByLength(32));
//        paymentRequest.setLimit_credit_pay("0");
        //计算签名
        Map<String, Object> data = CrmebUtil.objectToMap(paymentRequest);
        String sign = WxPayUtil.generateSignature(data, secretKey,"MD5");
        paymentRequest.setSign(sign);
        return paymentRequest;
    }

    private String getSysConfigValue(String key, Integer merId) {
        LambdaQueryWrapper<SystemConfig> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SystemConfig::getFormId,merId);
        queryWrapper.eq(SystemConfig::getName,key);
        queryWrapper.last("limit 1");
        SystemConfig systemConfig = systemConfigService.getOne(queryWrapper);
        if (systemConfig == null || StringUtils.isBlank(systemConfig.getValue())){
            throw new CrmebException("退款失败,密钥商户号等信息为空");
        }
        return systemConfig.getValue();
    }

    private static String getRandomStringByLength(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }
}
